#include "pwext.hpp"
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/signal.h>

struct Request
{
	bool isValid()
	{
		return false;
	}
	void handle()
	{ }
};
Request get_next_request()
{
	return Request();
}

pw::event started;

// [[ex05bc]]
// DEBUG descr The repeated signaling until the thread exits.
class worker : public pw::pwthread
{
public:
	worker() : 
		exit_flag_(false)
	{ }
	// ...
	void *execute()
	{
		while(!get_exit_flag()) {
	// DEBUG {
			fprintf(stderr, "worker thread in the loop\n");
			started.signal();
			pw::event delay;
			delay.msecwait(10); // artificially increase the race window
			fprintf(stderr, "worker thread is about to read the request\n");
	// DEBUG }
			Request r = get_next_request();

			if (get_exit_flag())
				break;
			if (!r.isValid())
				continue;

			// ... handle the request until need to sleep...
			if (mysleep(1000) != ETIMEDOUT)
				break; // it means, the exit was signaled
			// ... continue handling the request
		}
	// DEBUG {
		fprintf(stderr, "worker thread exits\n");
	// DEBUG }
		exit_confirm_event_.signal();
	}

	void stop()
	{
		{
			pw::lockmutex lm(exit_mutex_);
			exit_flag_ = true;
		}
		exit_event_.signal();
		do {
			if (id_ != 0)
	// DEBUG from
			{
				fprintf(stderr, "sending SIGUSR1\n");
	// DEBUG to
				// id_ is inherited from pw::thread
				pthread_kill(id_, SIGUSR1); 
	// DEBUG from
			}
	// DEBUG to
			else
				break;
		} while(exit_confirm_event_.msecwait(1) 
				== ETIMEDOUT);
	}

	// will return 0 if exit was signaled, ETIMEDOUT
	// otherwise
	int mysleep(int milliseconds)
	{
		return exit_event_.msecwait(milliseconds);
	}

protected:
	bool get_exit_flag()
	{
		pw::lockmutex lm(exit_mutex_);
		return exit_flag_;
	}

	bool exit_flag_;
	pw::pmutex exit_mutex_;
	pw::event exit_event_;
	pw::event exit_confirm_event_;
	// ...
};
// END

// DEBUG {
void dummyhandler(int sig)
{ }

int main(int argc, char **argv)
{
	// ...
	struct sigaction sa;
	sa.sa_handler = dummyhandler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0; // do not specify SA_RESTART !!!
	sigaction(SIGUSR1, &sa, NULL);
	// ...
	worker w;
	w.start();
	started.wait();
	w.stop();
	w.join();
}
// DEBUG }

/* Sample output (timing may vary, a SIGUSR1 may come after thread exit):
worker thread in the loop
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
sending SIGUSR1
worker thread is about to read the request
worker thread exits
*/
